package com.carsa.blackberry.util;

import java.util.Calendar;
import java.util.Date;

public class DateUtil {

    public static final int  EXPORT_TYPE_DEFAULT        = 0;
    public static final int  EXPORT_TYPE_ABAP           = 1;

    public static final int  EXPORT_DATE                = 1;
    public static final int  EXPORT_TIME                = 2;
    public static final int  EXPORT_DATE_AND_TIME       = 3;

    public static final int  DATE_ORDER_DD_MM_AAAA      = 1;
    public static final int  DATE_ORDER_AAAA_MM_DD      = 2;

    public static final int  TIME_ORDER_HH_MM_SS        = 1;
    public static final int  TIME_ORDER_SS_MM_HH        = 2;

    public static final char DATE_SEPARATOR_BAR         = '/';
    public static final char DATE_SEPARATOR_DOT         = '.';
    public static final char DATE_SEPARATOR_MIDDLE_LINE = '-';

    public static final char TIME_SEPARATOR_TWO_DOTS    = ':';
    public static final char TIME_SEPARATOR_DOT         = '.';

    public static final int  SECONDS_PER_DAY            = 86400;

    /**
     * @param aDate
     *            Un {@link Date} para exportar a algun formato preestablecido.
     * @param exportType
     *            El tipo de formato que se quiere. Ej: DateUtil.EXPORT_TYPE_ABAP
     * @return
     */
    public static String exportAs(Date aDate, int exportType, int thingsToExport) {

	switch (exportType) {
	case EXPORT_TYPE_ABAP:
	    return export(aDate, thingsToExport, DATE_ORDER_AAAA_MM_DD, DATE_SEPARATOR_MIDDLE_LINE,
		    TIME_ORDER_HH_MM_SS, TIME_SEPARATOR_TWO_DOTS);
	default:
	    return export(aDate, thingsToExport, DATE_ORDER_DD_MM_AAAA, DATE_SEPARATOR_BAR, TIME_ORDER_HH_MM_SS,
		    TIME_SEPARATOR_TWO_DOTS);
	}
    }

    /**
     * @param date
     * @param thingsToExport
     * @param dateOrder
     * @param dateSeparator
     * @param timeOrder
     * @param timeSeparator
     * @return
     */
    // TODO : Javadoc : Terminate this Javadoc.
    private static String export(Date date, int thingsToExport, int dateOrder, char dateSeparator, int timeOrder,
	    char timeSeparator) {

	String sDate = null;
	switch (thingsToExport) {
	case EXPORT_DATE:
	    sDate = exportDateAs(date, dateOrder, dateSeparator);
	    break;
	case EXPORT_TIME:
	    sDate = exportTimeAs(date, timeOrder, timeSeparator);
	    break;
	default:
	    sDate = exportDateAs(date, dateOrder, dateSeparator);
	    sDate += " " + exportTimeAs(date, timeOrder, timeSeparator);
	    break;
	}

	return sDate;
    }

    /**
     * @param aDate
     *            El {@link Date} que queremos convertir en {@link String}.
     * @param dateOrder
     *            El orden en que se quiere que aparezcan los dias/meses/anos. Ej: DateUtil.DATE_ORDER_DD_MM_AAAA
     * @param dateSeparator
     *            El estilo con el que se separa el dia del mes, y el mes del ano.
     * @return Un {@link String} en formato dd/mm/aaaa a raiz del {@link Date} que recibimos como parametro.
     */
    public static String exportDateAs(Date aDate, int dateOrder, char dateSeparator) {
	if (aDate == null)
	    return null;

	Calendar aCalendar = Calendar.getInstance();
	aCalendar.setTime(aDate);

	switch (dateOrder) {
	case DATE_ORDER_DD_MM_AAAA:
	    break;// Sale por default.
	case DATE_ORDER_AAAA_MM_DD:
	    return putPreffixWhenNeccessary(aCalendar.get(Calendar.YEAR)) + String.valueOf(dateSeparator)
		    + putPreffixWhenNeccessary(aCalendar.get(Calendar.MONTH) + 1) + String.valueOf(dateSeparator)
		    + putPreffixWhenNeccessary(aCalendar.get(Calendar.DATE));
	default:
	    break;
	}

	// Si llego a esta instancia, es que el switch quedo en DATE_ORDER_DD_MM_AAAA, o default.
	return putPreffixWhenNeccessary(aCalendar.get(Calendar.DATE)) + String.valueOf(dateSeparator)
	        + putPreffixWhenNeccessary(aCalendar.get(Calendar.MONTH) + 1) + String.valueOf(dateSeparator)
	        + aCalendar.get(Calendar.YEAR);
    }

    /**
     * @param aDate
     *            El {@link Date} que queremos convertir en {@link String}.
     * @param timeOrder
     *            El orden en que quiero que salgan las horas/minutos/segundos.
     * @param dateSeparator
     *            El estilo con el que se separan las horas, de los minutos, de los segundos.
     * @return
     */
    public static String exportTimeAs(Date aDate, int timeOrder, char timeSeparator) {
	Calendar aCalendar = Calendar.getInstance();
	aCalendar.setTime(aDate);

	switch (timeOrder) {
	case TIME_ORDER_HH_MM_SS:
	    break;// Sale por default.
	case TIME_ORDER_SS_MM_HH:
	    return putPreffixWhenNeccessary(aCalendar.get(Calendar.SECOND)) + String.valueOf(timeSeparator)
		    + putPreffixWhenNeccessary(aCalendar.get(Calendar.MINUTE)) + String.valueOf(timeSeparator)
		    + putPreffixWhenNeccessary(aCalendar.get(Calendar.HOUR));
	default:
	    break;
	}

	// Si llego a esta instancia, es que el switch quedo en DATE_ORDER_DD_MM_AAAA, o default.
	return putPreffixWhenNeccessary(aCalendar.get(Calendar.HOUR)) + String.valueOf(timeSeparator)
	        + putPreffixWhenNeccessary(aCalendar.get(Calendar.MINUTE)) + String.valueOf(timeSeparator)
	        + putPreffixWhenNeccessary(aCalendar.get(Calendar.SECOND));
    }

    /**
     * @param aDate
     *            Un {@link String} en formato dd/mm/aaaa para convertir a {@link Date}.
     * @param separatorStyle
     *            El estilo con el que se separa el dia del mes, y el mes del ano.
     * @return El {@link Date} que se genera a partir del {@link String} que recibimos como parametro.
     */
    public static Date getFromString(String aDate, char separatorStyle) {
	if (aDate == null)
	    return null;

	Calendar aCalendar = Calendar.getInstance();

	int firstBreakpoint = aDate.indexOf(separatorStyle);

	if (firstBreakpoint < 0)
	    return null;

	String date = aDate.substring(0, firstBreakpoint);
	aCalendar.set(Calendar.DATE, Integer.parseInt(date));

	String monthAndYear = aDate.substring(firstBreakpoint + 1);

	String month = monthAndYear.substring(0, monthAndYear.indexOf(separatorStyle));
	aCalendar.set(Calendar.MONTH, Integer.parseInt(month) - 1);

	String year = monthAndYear.substring(monthAndYear.indexOf(separatorStyle) + 1);
	aCalendar.set(Calendar.YEAR, Integer.parseInt(year));

	return aCalendar.getTime();
    }

    /**
     * @param aDate
     *            Un {@link Date} del cual quiero obtener un {@link Calendar}.
     * @return El {@link Calendar} correspondiente al {@link Date} seteado por parametro, pero con horas, minutos y
     *         segundos en 0.
     */
    public static Calendar getCalendarFrom(Date aDate) {
	Calendar aCalendar = Calendar.getInstance();

	aCalendar.setTime(aDate);
	aCalendar.set(Calendar.HOUR_OF_DAY, 0);
	aCalendar.set(Calendar.MINUTE, 0);
	aCalendar.set(Calendar.SECOND, 0);

	return aCalendar;
    }

    /**
     * @param aDate
     *            Un {@link Date} para comparar.
     * @param otherDate
     *            Otro {@link Date} para comparar.
     * @return Un int indicando la cantidad de dias que hay entre los {@link Date}s ingresados.
     */
    public static int daysBetween(Date aDate, Date otherDate) {
	Calendar aCalendar = getCalendarFrom(aDate);
	Calendar otherCalendar = getCalendarFrom(otherDate);

	long millis;
	if (aCalendar.before(otherCalendar))
	    millis = otherCalendar.getTime().getTime() - aCalendar.getTime().getTime();
	else
	    millis = aCalendar.getTime().getTime() - otherCalendar.getTime().getTime();

	return (int) millis / 1000 / SECONDS_PER_DAY;
    }

    /**
     * Agrega un 0 delante del numero que se pasa como parametro en number solo si este numero es de un digito. Es
     * decir, lo agrega para los numeros 0-9.
     * 
     * @param number
     *            El numero al que le quiero, si es necesario, agregar un cero adelante.
     * @return Un {@link String} con la representacion de number.
     */
    public static String putPreffixWhenNeccessary(int number) {
	if (number < 10)
	    return "0" + String.valueOf(number);

	return String.valueOf(number);
    }

}
